package com.wx.service.impl;

import com.github.pagehelper.PageInfo;
import com.google.common.collect.Lists;
import com.wx.common.BaseEntity;
import com.wx.common.PageParam;
import com.wx.common.SecurityUser;
import com.wx.constants.Constants;
import com.wx.domain.dto.RangeDto;
import com.wx.entity.*;
import com.wx.exception.BusinessException;
import com.wx.mapper.SysRangeMapper;
import com.wx.service.*;
import com.wx.utils.PageUtil;
import com.wx.utils.SnowFlakeUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;


/**
 * <p>Title:      SysRangeServiceImpl. </p>
 * <p>Description 范围表 </p>
 * <p>Copyright: Copyright (c) 2016</p>
 * <p>Company:    医百科技有限公司 </p>
 *
 * @author         yangwensheng@100doc.com.cn
 * @since      2021-03-22 10:51:46
 */
@Service
public class SysRangeServiceImpl extends BaseServiceImpl<SysRange> implements SysRangeService {

    @Resource
    private SysRangeMapper sysRangeMapper;

    @Resource
    private SysRangeHospitalService sysRangeHospitalService;

    @Resource
    private SysRangeAreaService sysRangeAreaService;

    @Resource
    private SysRangeNurseService sysRangeNurseService;

    @Resource
    private SysPatientService sysPatientService;

    @Override
    public PageInfo<SysRange> listPage(PageParam<SysRange> pageParam){
        SysRange sysRange = pageParam.getParam();
        PageInfo<SysRange> page = new PageInfo<>();
        List<SysRange> rangeList = sysRangeMapper.listPage(sysRange);
        if(!CollectionUtils.isEmpty(rangeList)){
            List<String> rangeIds = rangeList.stream().map(BaseEntity::getId).collect(Collectors.toList());
            List<SysRangeHospital> sysRangeHospitalList = sysRangeHospitalService.selectByRangeIds(rangeIds);


            Map<String, List<SysRangeHospital>> hospitalMap = sysRangeHospitalList.stream().collect(Collectors.groupingBy(SysRangeHospital::getRangeId));

            List<SysRangeArea> sysRangeAreaList = sysRangeAreaService.selectByRangeIds(rangeIds);
            Map<String, List<SysRangeArea>> areaMap = sysRangeAreaList.stream().collect(Collectors.groupingBy(SysRangeArea::getRangeId));

            List<SysRangeNurse> rangeNurses =  sysRangeNurseService.selectByRangeIds(rangeIds);
            Map<String, List<SysRangeNurse>> rangeNurseMap = rangeNurses.stream().collect(Collectors.groupingBy(SysRangeNurse::getRangeId));
            for (SysRange range : rangeList) {
                List<SysRangeArea> sysRangeAreas = areaMap.get(range.getId());
                if(!CollectionUtils.isEmpty(sysRangeAreas)){
                    String areaName = sysRangeAreas.stream().filter(f -> StringUtils.isNotEmpty(f.getAddressName())).map(SysRangeArea::getAddressName).reduce((x, y) -> x + "," + y).get();
                    range.setAreasName(areaName);
                    List<String> addressCodes = sysRangeAreas.stream().map(SysRangeArea::getAddressCode).collect(Collectors.toList());
                    range.setAreaCodeList(addressCodes);
                }
                List<SysRangeHospital> sysRangeHospitals = hospitalMap.get(range.getId());
                if(!CollectionUtils.isEmpty(sysRangeHospitals)){
                    String hospitalName = sysRangeHospitals.stream().filter(f -> StringUtils.isNotEmpty(f.getHospitalName())).map(SysRangeHospital::getHospitalName).reduce((x, y) -> x + "," + y).get();
                    range.setHospitalsName(hospitalName);
                    List<String> hospitalIds = sysRangeHospitals.stream().map(SysRangeHospital::getHospitalId).collect(Collectors.toList());
                    range.setHospitalIdList(hospitalIds);
                }
                List<SysRangeNurse> nurseList = rangeNurseMap.get(range.getId());
                if(!CollectionUtils.isEmpty(nurseList)){
                    String nurseName = nurseList.stream().filter(f -> StringUtils.isNotEmpty(f.getNurseName())).map(SysRangeNurse::getNurseName).reduce((x, y) -> x + "," + y).get();
                    range.setContactsName(nurseName);
                    String phone = nurseList.stream().filter(f -> StringUtils.isNotEmpty(f.getPhone())).map(SysRangeNurse::getPhone).reduce((x, y) -> x + "," + y).get();
                    range.setPhone(phone);
                    List<String> nurseIds = nurseList.stream().map(SysRangeNurse::getNurseId).collect(Collectors.toList());
                    range.setNurseIdList(nurseIds);
                }
            }
            if(StringUtils.isNotEmpty(sysRange.getContactsName())){
                rangeList = rangeList.stream().filter(f -> StringUtils.isNotEmpty(f.getContactsName()) && f.getContactsName().contains(sysRange.getContactsName())).collect(Collectors.toList());
            }
            if(StringUtils.isNotEmpty(sysRange.getPhone())){
                rangeList = rangeList.stream().filter(f -> StringUtils.isNotEmpty(f.getPhone())  && f.getPhone().contains(sysRange.getPhone())).collect(Collectors.toList());
            }
            page.setTotal(rangeList.size());
            List<SysRange> list = PageUtil.getPageListByParam(rangeList, pageParam.getPageNum(), pageParam.getPageSize());
            page.setPages(PageUtil.getTotalPage(list.size(),pageParam.getPageSize()));
            page.setList(list);
        }
        return page;
    }


    @Override
    public List<SysRange> export(SysRange sysRange) {
        List<SysRange> rangeList = sysRangeMapper.listPage(sysRange);
        if(!CollectionUtils.isEmpty(rangeList)){
            List<String> rangeIds = rangeList.stream().map(BaseEntity::getId).collect(Collectors.toList());
            List<SysRangeHospital> sysRangeHospitalList = sysRangeHospitalService.selectByRangeIds(rangeIds);

            Map<String, List<SysRangeHospital>> hospitalMap = sysRangeHospitalList.stream().collect(Collectors.groupingBy(SysRangeHospital::getRangeId));

            List<SysRangeArea> sysRangeAreaList = sysRangeAreaService.selectByRangeIds(rangeIds);
            Map<String, List<SysRangeArea>> areaMap = sysRangeAreaList.stream().collect(Collectors.groupingBy(SysRangeArea::getRangeId));

            List<SysRangeNurse> rangeNurses =  sysRangeNurseService.selectByRangeIds(rangeIds);
            Map<String, List<SysRangeNurse>> rangeNurseMap = rangeNurses.stream().collect(Collectors.groupingBy(SysRangeNurse::getRangeId));
            for (SysRange range : rangeList) {
                List<SysRangeArea> sysRangeAreas = areaMap.get(range.getId());
                if(!CollectionUtils.isEmpty(sysRangeAreas)){
                    String areaName = sysRangeAreas.stream().filter(f -> StringUtils.isNotEmpty(f.getAddressName())).map(SysRangeArea::getAddressName).reduce((x, y) -> x + "," + y).get();
                    range.setAreasName(areaName);
                    List<String> addressCodes = sysRangeAreas.stream().map(SysRangeArea::getAddressCode).collect(Collectors.toList());
                    range.setAreaCodeList(addressCodes);
                }
                List<SysRangeHospital> sysRangeHospitals = hospitalMap.get(range.getId());
                if(!CollectionUtils.isEmpty(sysRangeHospitals)){
                    String hospitalName = sysRangeHospitals.stream().filter(f -> StringUtils.isNotEmpty(f.getHospitalName())).map(SysRangeHospital::getHospitalName).reduce((x, y) -> x + "," + y).get();
                    range.setHospitalsName(hospitalName);
                    List<String> hospitalIds = sysRangeHospitals.stream().map(SysRangeHospital::getHospitalId).collect(Collectors.toList());
                    range.setHospitalIdList(hospitalIds);
                }
                List<SysRangeNurse> nurseList = rangeNurseMap.get(range.getId());
                if(!CollectionUtils.isEmpty(nurseList)){
                    String nurseName = nurseList.stream().filter(f -> StringUtils.isNotEmpty(f.getNurseName())).map(SysRangeNurse::getNurseName).reduce((x, y) -> x + "," + y).get();
                    range.setContactsName(nurseName);
                    String phone = nurseList.stream().filter(f -> StringUtils.isNotEmpty(f.getPhone())).map(SysRangeNurse::getPhone).reduce((x, y) -> x + "," + y).get();
                    range.setPhone(phone);
                    List<String> nurseIds = nurseList.stream().map(SysRangeNurse::getNurseId).collect(Collectors.toList());
                    range.setNurseIdList(nurseIds);
                }
            }
            if(StringUtils.isNotEmpty(sysRange.getContactsName())){
                rangeList = rangeList.stream().filter(f -> StringUtils.isNotEmpty(f.getContactsName()) && f.getContactsName().equals(sysRange.getContactsName())).collect(Collectors.toList());
            }
            if(StringUtils.isNotEmpty(sysRange.getPhone())){
                rangeList = rangeList.stream().filter(f -> StringUtils.isNotEmpty(f.getPhone())  && f.getPhone().equals(sysRange.getPhone())).collect(Collectors.toList());
            }
        }
        return rangeList;
    }

    @Override
    public List<SysRange> selectByIds(List<String> rangeIds) {
        return sysRangeMapper.selectByIds(rangeIds);
    }


    @Override
    @Transactional
    public int deleteById(String id,String userName,String userId){
        Optional<SysRange> optional = sysRangeMapper.selectByKeyOptional(id);
        optional.orElseThrow(() -> new BusinessException("非法的参数"));
        SysRange sysRange = optional.get();
        sysRange.setUpdateDate(new Date());
        sysRange.setDelFlag(Constants.DELETE_YES);

        // 删除范围和区域的绑定关系
        sysRangeAreaService.deleteByRangeId(id);

        // 删除范围和机构的绑定关系
        sysRangeHospitalService.deleteByRangeId(id);

        // 删除范围和护士的绑定关系
        sysRangeNurseService.deleteByRangeId(id);
        return sysRangeMapper.updateByPrimaryKeySelective(sysRange);
    }

    @Override
    @Transactional
    public int saveRange(RangeDto rangeDto, SecurityUser securityUser) {
        if(CollectionUtils.isEmpty(rangeDto.getHospitalList())){
            throw new BusinessException("所选医院不能为空");
        }
        if(CollectionUtils.isEmpty(rangeDto.getAddressCodeList())){
            throw new BusinessException("所选区县不能为空");
        }


        SysRange sysRange = new SysRange();
        sysRange.setId(SnowFlakeUtil.getStringId());
        sysRange.setRangeName(rangeDto.getRangeName());
        sysRange.setCreator(securityUser.getRealName());
        sysRange.setCreateBy(securityUser.getUserId());
        sysRange.setUpdater(securityUser.getRealName());
        sysRange.setUpdateBy(securityUser.getUserId());
        sysRangeMapper.insertSelective(sysRange);

        List<SysRangeNurse> sysRangeNurseList = Lists.newArrayList();
        for (String contactsId : rangeDto.getContactsIds().stream().distinct().collect(Collectors.toList())) {
            // 校验护士是否已经绑定了所属范围
            SysRangeNurse sysRangeNurse = sysRangeNurseService.selectByNurseId(contactsId);
            if(sysRangeNurse != null){
                throw new BusinessException("该护士已经有所属的范围了，不能绑定新的范围");
            }
            SysRangeNurse rangeNurse = new SysRangeNurse();
            rangeNurse.setRangeId(sysRange.getId());
            rangeNurse.setNurseId(contactsId);
            sysRangeNurseList.add(rangeNurse);
        }
        sysRangeNurseService.batchSave(sysRangeNurseList);

        List<SysRangeHospital> sysRangeHospitals = Lists.newArrayList();
        SysRangeHospital sysRangeHospital = null;
        for (String hospitalId : rangeDto.getHospitalList().stream().distinct().collect(Collectors.toList())) {
            // 校验机构是否已经绑定了
            SysRangeHospital rangeHospital = sysRangeHospitalService.selectByHospitalId(hospitalId);
            if(rangeHospital != null){
                throw new BusinessException(rangeHospital.getHospitalName() + "已经绑定到了其他区域，请先进行解绑");
            }

            sysRangeHospital = new SysRangeHospital();
            sysRangeHospital.setRangeId(sysRange.getId());
            sysRangeHospital.setHospitalId(hospitalId);
            sysRangeHospitals.add(sysRangeHospital);
        }

        sysRangeHospitalService.batchSave(sysRangeHospitals);

        List<SysRangeArea> sysRangeAreaList = Lists.newArrayList();
        SysRangeArea sysRangeArea = null;
        for (String address : rangeDto.getAddressCodeList().stream().distinct().collect(Collectors.toList())) {
            String[] split = address.split(",");
            sysRangeArea = new SysRangeArea();
            sysRangeArea.setRangeId(sysRange.getId());
            sysRangeArea.setProvinceCode(split[0]);
            sysRangeArea.setCityCode(split[1]);
            sysRangeArea.setAreaCode(split[2]);
            sysRangeAreaList.add(sysRangeArea);
        }
        sysRangeAreaService.batchSave(sysRangeAreaList);
        return 1;
    }

    @Override
    public SysRange selectRangeByRangeId(String rangeId) {
        return sysRangeMapper.selectRangeByRangeId(rangeId);
    }

    @Override
    @Transactional
    public void updateRange(RangeDto rangeDto, SecurityUser securityUser) {
        if(CollectionUtils.isEmpty(rangeDto.getHospitalList())){
            throw new BusinessException("所选医院不能为空");
        }
        if(CollectionUtils.isEmpty(rangeDto.getAddressCodeList())){
            throw new BusinessException("所选区县不能为空");
        }
        // 校验护士是否已经绑定了所属范围
        SysRange range = sysRangeMapper.selectByPrimaryKey(rangeDto.getId());
        if(range == null){
            throw new BusinessException("无效的范围id");
        }

        range.setRangeName(rangeDto.getRangeName());
        range.setUpdater(securityUser.getRealName());
        range.setUpdateBy(securityUser.getUserId());
        sysRangeMapper.updateByPrimaryKeySelective(range);

        sysRangeNurseService.deleteByRangeId(range.getId());
        List<SysRangeNurse> sysRangeNurseList = Lists.newArrayList();
        for (String contactsId : rangeDto.getContactsIds().stream().distinct().collect(Collectors.toList())) {
            // 校验护士是否已经绑定了所属范围
            SysRangeNurse sysRangeNurse = sysRangeNurseService.selectByNurseId(contactsId);
            if(sysRangeNurse != null){
                throw new BusinessException("该护士已经有所属的范围了，不能绑定新的范围");
            }
            SysRangeNurse rangeNurse = new SysRangeNurse();
            rangeNurse.setRangeId(range.getId());
            rangeNurse.setNurseId(contactsId);
            sysRangeNurseList.add(rangeNurse);
        }
        sysRangeNurseService.batchSave(sysRangeNurseList);

        sysRangeHospitalService.deleteByRangeId(range.getId());

        List<SysRangeHospital> sysRangeHospitals = Lists.newArrayList();
        SysRangeHospital sysRangeHospital = null;
        for (String hospitalId : rangeDto.getHospitalList().stream().distinct().collect(Collectors.toList())) {
            // 校验机构是否已经绑定了
            SysRangeHospital rangeHospital = sysRangeHospitalService.selectByHospitalId(hospitalId);
            if(rangeHospital != null){
                throw new BusinessException(rangeHospital.getHospitalName() + "已经绑定到了其他区域，请先进行解绑");
            }

            sysRangeHospital = new SysRangeHospital();
            sysRangeHospital.setRangeId(range.getId());
            sysRangeHospital.setHospitalId(hospitalId);
            sysRangeHospitals.add(sysRangeHospital);
        }

        List<SysPatient> sysPatients = sysPatientService.selectByHospitalIds(rangeDto.getHospitalList().stream().distinct().collect(Collectors.toList()));
        List<String> patientIds = sysPatients.stream().map(BaseEntity::getId).collect(Collectors.toList());
        if(!CollectionUtils.isEmpty(patientIds)){
            sysPatientService.batchUpdateNurseId(patientIds,rangeDto.getContactsIds().stream().distinct().collect(Collectors.toList()).stream().findFirst().get());
        }

        sysRangeHospitalService.batchSave(sysRangeHospitals);

        sysRangeAreaService.deleteByRangeId(range.getId());
        List<SysRangeArea> sysRangeAreaList = Lists.newArrayList();
        SysRangeArea sysRangeArea = null;
        for (String address : rangeDto.getAddressCodeList().stream().distinct().collect(Collectors.toList())) {
            String[] split = address.split(",");
            sysRangeArea = new SysRangeArea();
            sysRangeArea.setRangeId(range.getId());
            sysRangeArea.setProvinceCode(split[0]);
            sysRangeArea.setCityCode(split[1]);
            sysRangeArea.setAreaCode(split[2]);
            sysRangeAreaList.add(sysRangeArea);
        }
        sysRangeAreaService.batchSave(sysRangeAreaList);
    }

}
